package com.liruo.learn.spring.mvc.controller.valid.validatedcommonbean;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessorX;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;

/**
 * @Author:liruo
 * @Date:2023-06-09-23:35:10
 * @Desc
 */
@Configuration
@Slf4j
public class ValidatedConfiguration {
    /**
     *   Validated属于spring的, 因此如果是@Validated我就禁止DataBinder进行校验
     *      方便区别在类上使用@Validated已经对所有方法进行拦截校验的 和 类上没有@Validated的
     *      类上没有@Validated的就使用@Valid进行校验
     *   主要是因为对方法进行校验Valid规范仅仅是做了定义, 而没有实现, 因此对方法进行校验是实现者独有的, 因此使用其独有的注解
     */
    @Autowired
    public void validatedCommonBeanWebMvcConfigurer(RequestMappingHandlerAdapter requestMappingHandlerAdapter){
        //注意 requestMappingHandlerAdapter.getArgumentResolvers()是UnmodifiableList
        //找到默认的ServletModelAttributeMethodProcessor
        ArrayList<HandlerMethodArgumentResolver> handlerMethodArgumentResolvers = new ArrayList<>(Objects.requireNonNull(requestMappingHandlerAdapter.getArgumentResolvers()));
        int toReplaceIndex = -1;
        for (int i = handlerMethodArgumentResolvers.size() - 1; i >= 0; i--) {
            if(handlerMethodArgumentResolvers.get(i) instanceof ServletModelAttributeMethodProcessor){
                toReplaceIndex = i;
                break;
            }
        }
        if(toReplaceIndex == -1){
            log.debug("error, requestMappingHandlerAdapter has not ServletModelAttributeMethodProcessor, argumentResolvers={}", handlerMethodArgumentResolvers);
            return;
        }

        //重新设置默认的ServletModelAttributeMethodProcessor
        try {
            //先复制属性
            Field field = ReflectionUtils.findField(ServletModelAttributeMethodProcessorX.class, "annotationNotRequired");
            field.setAccessible(true);
            //修改默认的, 重写validateIfApplicable方法
            boolean annotationNotRequired = (boolean) field.get(handlerMethodArgumentResolvers.get(toReplaceIndex));
            handlerMethodArgumentResolvers.set(toReplaceIndex, new ServletModelAttributeMethodProcessorX(annotationNotRequired));
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

        //重新设置
        requestMappingHandlerAdapter.setArgumentResolvers(Collections.unmodifiableList(handlerMethodArgumentResolvers));
    }

}
